1 /* 2 Copyright: Marcelo S. N. Mancini (Hipreme|MrcSnm), 2018 - 2021 3 License: [https://creativecommons.org/licenses/by/4.0/|CC BY-4.0 License]. 4 Authors: Marcelo S. N. Mancini 5 6 Copyright Marcelo S. N. Mancini 2018 - 2021. 7 Distributed under the CC BY-4.0 License. 8 (See accompanying file LICENSE.txt or copy at 9 https://creativecommons.org/licenses/by/4.0/ 10 */ 11 module hip.util.array; 12 private import hip.util.conv : to; 13 14 /** 15 * Uses accessor on the array to find an element 16 */ 17 int indexOf(string accessor, T, Q)(T[] arr, Q element, int startIndex = 0) 18 { 19 static if(accessor != "") 20 enum op = "."~accessor; 21 else 22 enum op = accessor; 23 const size_t len = arr.length; 24 for(size_t i = startIndex; i < len; i++) 25 mixin("if(arr[i]"~op~" == element)return cast(int)i;"); 26 return -1; 27 } 28 /** 29 * Returns index of element if it finds or returns -1 if not 30 */ 31 int indexOf(T)(in T[] arr, T element, int startIndex = 0) pure nothrow @nogc 32 { 33 if(startIndex < 0) 34 return -1; 35 for(int i = startIndex; i < arr.length; i++) 36 if(arr[i] == element) 37 return i; 38 return -1; 39 } 40 41 import std.typecons: isTuple; 42 ///Index of for tuples 43 int indexOf(T, V)(in T tuple, V value) pure nothrow @nogc if(isTuple!T) 44 { 45 foreach(i, v; tuple) 46 { 47 static if(is(typeof(v) == V)) 48 if(v == value) 49 return i; 50 } 51 return -1; 52 } 53 54 55 56 int lastIndexOf(T)(T[] arr, T element, int startIndex = -1) 57 { 58 const size_t len = arr.length; 59 if(len==0)return-1; 60 if(startIndex < 0) startIndex = (cast(int)len - 1); 61 for(int i = startIndex; i >= 0; i--) 62 if(arr[i] == element) 63 return i; 64 return -1; 65 } 66 67 /** 68 * Should work only for numerics 69 */ 70 int binarySearch(T)(in T[] arr, T element) @nogc @safe nothrow 71 { 72 uint l = 0; 73 uint r = arr.length; 74 uint m; 75 while(l <= r) 76 { 77 m = cast(uint)((l+r)/2); 78 if(arr[m] < element) 79 l = m + 1; 80 else if(arr[m] > element) 81 r = m - 1; 82 else if(arr[m] == element) 83 return m; 84 } 85 86 return -1; 87 } 88 89 bool swapAt(T)(T[] arr, int index1, int index2) @nogc @safe nothrow 90 { 91 if(index1 == index2 || index1 < 0 || index1 >= arr.length || index2 < 0 || index2 >= arr.length) 92 return false; 93 T temp = arr[index1]; 94 arr[index1] = arr[index2]; 95 arr[index2] = temp; 96 return true; 97 } 98 99 /** 100 * Returns if swap was succesful 101 */ 102 bool swapElementsFromArray(T)(T[] arr, T element1, T element2) @nogc @safe nothrow 103 { 104 long index1 = arr.indexOf(element1); 105 long index2 = arr.indexOf(element2); 106 107 if(index1 != -1 && index2 != 1) 108 { 109 T temp = arr[index1]; 110 arr[index1] = arr[index2]; 111 arr[index2] = temp; 112 return true; 113 } 114 return false; 115 } 116 117 118 bool popFront(T)(ref T[] arr, out T val) 119 { 120 import hip.util.memory; 121 if(arr.length == 0) 122 return false; 123 val = arr[0]; 124 memcpy(arr.ptr, arr.ptr+1, (cast(int)arr.length-1)*T.sizeof); 125 arr.length--; 126 return true; 127 } 128 bool popFront(T)(ref T[] arr) 129 { 130 T val; 131 return popFront(arr, val); 132 } 133 bool remove(T)(ref T[] arr, T val) 134 { 135 for(size_t i = 0; i < arr.length; i++) 136 { 137 if(arr[i] == val) 138 { 139 for(size_t z = 0; z+i < cast(int)arr.length-1; z++) 140 arr[z+i] = arr[z+i+1]; 141 arr.length--; 142 return true; 143 } 144 } 145 return false; 146 } 147 148 bool remove(T)(ref T[] arr, const(T)* val) 149 { 150 for(size_t i = 0; i < arr.length; i++) 151 { 152 if(&arr[i] == val) 153 { 154 for(size_t z = 0; z+i < cast(int)arr.length-1; z++) 155 arr[z+i] = arr[z+i+1]; 156 arr.length--; 157 return true; 158 } 159 } 160 return false; 161 } 162 163 pragma(inline, true) 164 bool contains(T)(in T[] arr, T val) pure nothrow @nogc {return arr.indexOf(val) != -1;} 165 166 pragma(inline, true) 167 bool contains(T, V)(in T[] tuple, V val) pure nothrow @nogc {return tuple.indexOf(val) != -1;} 168 169 170 /** 171 * Compare a array of structures member with a target value 172 */ 173 bool contains(string accessor, T, Q)(ref T[] arr, Q val) 174 { 175 for(size_t i = 0; i < arr.length; i++) 176 { 177 if(__traits(getMember, arr[i], accessor) == val) 178 return true; 179 } 180 return false; 181 } 182 183 /** 184 * Compare two different structures accessing different members 185 */ 186 bool contains(string accessorA, string accessorB, T, Q)(ref T[] arr, Q val) 187 { 188 for(size_t i = 0; i < arr.length; i++) 189 { 190 if(__traits(getMember, arr[i], accessorA) == __traits(getMember, val, accessorB)) 191 return true; 192 } 193 return false; 194 } 195 196 pragma(inline, true) bool isEmpty(T)(in T[] arr){return arr.length == 0;} 197 198 199 import std.traits:ForeachType; 200 ForeachType!(T)[] array(T)(T range) 201 { 202 typeof(return) ret; 203 foreach(r;range) 204 ret~= r; 205 return ret; 206 } 207 208 string join(T)(T[] arr, string separator = "") 209 { 210 import hip.util.conv; 211 string ret; 212 if(arr.length == 0) return ""; 213 214 ret = toString(arr[0]); 215 for(int i = 1; i < arr.length; i++) 216 { 217 ret~= separator; 218 ret~= arr[i]; 219 } 220 return ret; 221 } 222 223 string join(T)(T[] arr, char separator) 224 { 225 char[1] temp = separator; 226 return join(arr, cast(string)temp); 227 } 228 229 230 void printArrayWithoutValues(T)(const T[] arr, T[] ignoreValues...) 231 { 232 import hip.console.log; 233 string str = "["; 234 MainLoop: foreach (val; arr) 235 { 236 foreach (arg; ignoreValues) 237 if(val == arg) //Ignore if value is in the loop list 238 continue MainLoop; 239 str~= to!string(val) ~", "; 240 } 241 str~= "]"; 242 const int index = lastIndexOf(str, ','); 243 if(index == -1) 244 logln("[]"); 245 else 246 logln(str[0..index] ~ str[index+2..$]); 247 } 248 249 unittest 250 { 251 assert(indexOf([2, 3, 4], 3) == 1); 252 assert(swapElementsFromArray([5, 10, 9], 10, 9)); 253 assert(lastIndexOf([2, 3, 3, 4], 4) == 3); 254 }